#include "modulator.h"

// !!!!!!!!!!!!!!! использовать код Грея!

Modulator::Modulator(qlonglong q, qreal energy, QObject *parent) :
  QObject(parent),
  m_q(q),
  m_E(energy),
  m_sqrtQDown(0),
  m_m( log2(q) )
{
  if (m_m % 2) { // прореженное сигнальное множество
    m_sqrtQDown = qSqrt( m_q / 2.0 );
    m_sqrtQ     = qSqrt( m_q * 2.0 );
    m_l         = qSqrt( (6.0 * m_E) / (2.0*m_q - 1.0) ); // расстояние между сигнальными
                                                          // точками
    m_delta     = m_l * qSqrt(2.0);                       // минимальное расстояние между
                                                          // сигнальными точками
  }
  else {         // цельное сигнальное множество
    m_sqrtQ = qSqrt(m_q);

    // E = ( (d^2) * (q - 1) ) / 6.0
    m_delta = qSqrt( (6.0 * m_E) / (m_q - 1.0) ); // минимальное расстояние между
                                                  // сигнальными точками
    m_l     = m_delta;                            // расстояние между сигнальными точками
  }

  m_A = ( m_l*( m_sqrtQ-1.0 ) ) / 2.0; // амплитуда сигналов QAM
}

// модуляция
// предусловие: элементы кодового слова не должны превышать значения объема сигнального
//              алфавита
// постусловие: сигнальные точки должны ограничиваться амплитудой QAM
QVector<QPointF> Modulator::modulation(const QVector<qlonglong> a) {
  QVector<QPointF> res;

  qlonglong i;        // номер сигнала
  qlonglong i1, i2;   // индексы сигнальной точки
  QPointF   si;       // сигнальная точка
  for (int k = 0; k < a.size(); ++k) {
#ifdef ERRS
    if ( a.at(k) >= m_q || a.at(k) < 0 ) { // проверка предусловия
      error("Modulator::modulation(): номер сигнала выходит за пределы сигнального "
            "множества.");
    }
#endif

    i = a.at(k);

    if ( m_m % 2 ) { // прореженное сигнальное множество
      // i = i2*sqrtQDown + i1/2;
      i2 = i / m_sqrtQDown;
      i1 = 2 * (i % m_sqrtQDown) + i2 % 2;
//      i1 = 2 * (i % m_sqrtQDown) + (i2 + 1) % 2;
    }
    else {           // цельное сигнальное множество
      i2 = i / m_sqrtQ;
      i1 = i % m_sqrtQ;
    }

    // si.x и si.y лежат на отрезке [-A, A]
    si.setX(  ( m_A * 2.0 * i1 ) / (m_sqrtQ-1.0) - m_A  );
    si.setY(  ( m_A * 2.0 * i2 ) / (m_sqrtQ-1.0) - m_A  );

#ifdef ERRS
    if ( si.x() > m_A || si.x() < -m_A || si.y() > m_A || si.y() < -m_A ) { // постусловие
      error("Modulator::modulation(): сигнальная точка выходит за пределы амплитуды.");
    }
#endif

    res.append(si);
  }

  return res;
}
